import React, { useEffect, useState, createContext } from 'react'

// 子组件1（父子通信）：
function SonCompOne(props) {
  // 父子通信：
  const { count, list, obj, handleAdd } = props

  const addFatherCount = () => {
    handleAdd(1)
  }

  // 兄弟通信：
  const { getSonOneData } = props
  const [toSonTwoData] = useState('这是son1给son2的数据')
  const toSonTwoDataFn = () => {
    // 将数据传给父组件
    getSonOneData(toSonTwoData)
  }
  useEffect(() => {
    toSonTwoDataFn()
  }, [])

  return (
    <div>
      <div>父组件数据：{count}</div>
      <div>
        <button onClick={addFatherCount}>点击修改</button>
      </div>
      <div>父组件对象name值：{obj.name}</div>
      <ul>
        {list.map((item) => {
          return <li key={item}>{item}</li>
        })}
      </ul>
    </div>
  )
}

// 子组件2（兄弟通信，1传2）
function SonCompTwo(props) {
  const { sonOneData } = props
  return (
    <div>
      <div>这是子组件2</div>
      <div>在子组件2中得到数据：{sonOneData}</div>
    </div>
  )
}

// 子组件3（Context）
// 1、解构出来 Provider, Consumer
const { Provider, Consumer } = createContext()
function CompThree(props) {
  return (
    <div>
      <div>这是子组件3，里面包裹了子组件4</div>
      {/* 组件3中包裹组件4 */}
      <CompFour />
    </div>
  )
}

// 子组件4（Context）
function CompFour(props) {
  return (
    <div>
      <div>这是子组件4，里面使用了 Context 数据</div>
      {/* 通过 Consumer 使用数据（固定写法） */}
      <Consumer>{(value) => <div>{value}</div>}</Consumer>
    </div>
  )
}

// 父组件
function App() {
  // 父子通信
  const [count, setCount] = useState(10)
  const [list] = useState([1, 2, 3])
  const [obj] = useState({ name: '哈哈哈' })

  const addCount = (num) => {
    setCount(count + num)
  }

  // 兄弟通信
  // 设置一个值，得到子组件1的数据
  const [sonOneData, setSonOneData] = useState('')
  const getSonOneData = (data) => {
    setSonOneData(data)
  }

  // Context
  // 1、导入以及初始化。（在子组件3上面已经用了）
  // 2、使用 Provider 包裹根组件（在下面父组件的return处已经用了）
  // 3、定义传的数据，写在 Provider 的 value 处
  const contextValue = '这是使用Context的值'

  return (
    // 2、使用 Provider 包裹根组件
    <Provider value={contextValue}>
      <div>
        {/* 父子通信 */}
        <h3>父子通信</h3>
        <SonCompOne
          count={count}
          list={list}
          obj={obj}
          handleAdd={addCount}
          getSonOneData={getSonOneData}
        />

        {/* 兄弟通信 */}
        <h3>兄弟通信</h3>
        <SonCompTwo sonOneData={sonOneData} />

        {/* Context（父传子、孙或父传更下层） */}
        {/* 
          使用步骤：
          1、创建 Context 对象，导出 Provider 和 Consumer 对象
            import React, { createContext } from 'react'
            const {Provider, Consumer} = createContext()
          2、使用 Provider 包裹根组件并提供数据
            <Provider value={message} >
              根组件
            </Provider>
          3、需要用到数据的组件使用 Consumer 包裹获取数据
            <Consumer>
              {value => 基于 context 值进行渲染}
            </Consumer>
        */}
        {/* App -> 组件3 -> 组件4 */}
        {/* App数据 -> 组件4 */}
        {/* 
          1、导入以及初始化。（在子组件3上面已经用了）
          2、使用 Provider 包裹根组件（在下面父组件的return处已经用了）
          3、定义传的数据，写在 Provider 的 value 处
          4、在需要使用该数据的组件上，使用 Consumer 包裹以及使用
        */}
        <h3>Context</h3>
        <CompThree />
      </div>
    </Provider>
  )
}

export default App
